﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;

using Microsoft.Cci;
using Microsoft.Cci.MutableCodeModel;

using SimpleIR;

namespace CCITranslator
{
	public static class CCIExtractor
	{
		private const string RuntimeDLLFile = @"CSharpLibs.dll";
		private const string RuntimePDBFile = @"CSharpLibs.pdb";

		public static IRProgram Extract(string exefile, string BaseDir)
		{
			////
			Console.WriteLine("Loading Program: " + System.IO.Path.GetFileName(exefile));

			IRProgram p = null;

			System.IO.Stream pdbStream = null;
			PdbReader pdbReader = null;
			System.IO.Stream supportpdbStream = null;
			PdbReader supportpdbReader = null;
			PeReader.DefaultHost host = null;

			try
			{
				host = new PeReader.DefaultHost();

				IModule module = host.LoadUnitFrom(exefile) as IModule;
				if(module == null || module == Dummy.Module || module == Dummy.Assembly)
					throw new ArgumentException(exefile + " is not a PE file containing a CLR assembly, or an error occurred when loading it.");

				string pdbFile = System.IO.Path.ChangeExtension(module.Location, "pdb");

				if(!System.IO.File.Exists(pdbFile))
					throw new ArgumentException("Could not load the PDB file for '" + module.Name.Value + "'.");

				pdbStream = System.IO.File.OpenRead(pdbFile);
				pdbReader = new PdbReader(pdbStream, host);

				string supportexe = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(exefile), RuntimeDLLFile);
				IModule supportMod = host.LoadUnitFrom(supportexe) as IModule;
				if(supportMod == null || supportMod == Dummy.Module || supportMod == Dummy.Assembly)
				{
					Console.WriteLine("Support Module load Failed");
					System.Environment.Exit(1);
				}

				string supportpdb = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(exefile), RuntimePDBFile);
				if(!System.IO.File.Exists(pdbFile))
					throw new ArgumentException("Could not load the PDB file for '" + supportpdb + "'.");

				supportpdbStream = System.IO.File.OpenRead(supportpdb);
				supportpdbReader = new PdbReader(supportpdbStream, host);

				////////////////////
				//Rewrite File
				CCILoader loader = new CCILoader(host, pdbReader, supportMod, supportpdbReader);
				p = loader.Process(module);
			}
			finally
			{
				if(host != null)
					host.Dispose();
				if(pdbStream != null)
					pdbStream.Dispose();
				if(supportpdbReader != null)
					supportpdbReader.Dispose();
			}

			return p;
		}
	}

	/// <summary>
	/// Our walker for the metadata tree.
	/// </summary>
	public class CCILoader
	{
		private IRProgram m_irprog = null;
		private Queue<TypeInstInfo> m_toProcessTypes = null;

		private HashSet<Tuple<IRInvokeIdentity, IRType>> m_pendinganddonemwethods = null;
		private Queue<MethodInstInfo> m_toProcessMethods = null;

		internal IRType m_optionalT0ReplType = null;

		private PdbReader m_modulepdb;
		private PdbReader m_builtinpdb;

		internal IMethodDefinition ObjectEqualityComparerDefaultByRef;
		internal IMethodDefinition ObjectEqualityComparer;
		internal IMethodDefinition ObjectEqualityComparerWEQ;
		internal IMethodDefinition StructEqualityComparerDefaultByValue;
		internal IMethodDefinition StructEqualityComparer;
		internal IMethodDefinition StructEqualityComparerWEQ;

		internal IMethodDefinition ObjectEqualityComparerDefaultByRef_HashCode;
		internal IMethodDefinition ObjectEqualityComparer_HashCode;
		internal IMethodDefinition ObjectEqualityComparerWEQ_HashCode;
		internal IMethodDefinition StructEqualityComparerDefaultByValue_HashCode;
		internal IMethodDefinition StructEqualityComparer_HashCode;
		internal IMethodDefinition StructEqualityComparerWEQ_HashCode;

		internal IMethodDefinition ObjectComparer;
		internal IMethodDefinition StructComparer;

		/// <summary>
		/// The main method to load a .net assembly and get an IRProgram representation, null if something goes wrong.
		/// </summary>
		public CCILoader(IMetadataHost host, PdbReader modulepdb, IModule supportMod, PdbReader supportPDB)
			: base()
		{
			//initialize reference counter
			IRProgram.InitializeRefCounter();

			this.m_irprog = new IRProgram();
			this.m_toProcessTypes = new Queue<TypeInstInfo>();

			this.m_pendinganddonemwethods = new HashSet<Tuple<IRInvokeIdentity, IRType>>();
			this.m_toProcessMethods = new Queue<MethodInstInfo>();

			this.m_modulepdb = modulepdb;
			this.m_builtinpdb = supportPDB;

			//load all the methods that will require patching
			foreach(ITypeDefinition tdd in supportMod.GetAllTypes())
			{
				String tyname = tdd.ToString();
				foreach(IMethodDefinition mmd in tdd.Methods)
				{
					String mname = mmd.Name.Value;

					if(tyname.Equals("System.Collections.Generic.ObjectEqualityComparerDefaultByRef"))
					{
						if(mname.Equals("DefaultEquals"))
							this.ObjectEqualityComparerDefaultByRef = mmd;
						else if(mname.Equals("DefaultGetHashCode"))
							this.ObjectEqualityComparerDefaultByRef_HashCode = mmd;
						else
						{ ;}
					}
					else if(tyname.Equals("System.Collections.Generic.ObjectEqualityComparer"))
					{
						if(mname.Equals("DefaultEquals"))
							this.ObjectEqualityComparer = mmd;
						else if(mname.Equals("DefaultGetHashCode"))
							this.ObjectEqualityComparer_HashCode = mmd;
						else
						{ ;}
					}
					else if(tyname.Equals("System.Collections.Generic.ObjectEqualityComparerWEQ"))
					{
						if(mname.Equals("DefaultEquals"))
							this.ObjectEqualityComparerWEQ = mmd;
						else if(mname.Equals("DefaultGetHashCode"))
							this.ObjectEqualityComparerWEQ_HashCode = mmd;
						else
						{ ;}
					}
					else if(tyname.Equals("System.Collections.Generic.StructEqualityComparerDefaultByValue"))
					{
						if(mname.Equals("DefaultEquals"))
							this.StructEqualityComparerDefaultByValue= mmd;
						else if(mname.Equals("DefaultGetHashCode"))
							this.StructEqualityComparerDefaultByValue_HashCode = mmd;
						else
						{ ;}
					}
					else if(tyname.Equals("System.Collections.Generic.StructEqualityComparer"))
					{
						if(mname.Equals("DefaultEquals"))
							this.StructEqualityComparer = mmd;
						else if(mname.Equals("DefaultGetHashCode"))
							this.StructEqualityComparer_HashCode = mmd;
						else
						{ ;}
					}
					else if(tyname.Equals("System.Collections.Generic.StructEqualityComparerWEQ"))
					{
						if(mname.Equals("DefaultEquals"))
							this.StructEqualityComparerWEQ = mmd;
						else if(mname.Equals("DefaultGetHashCode"))
							this.StructEqualityComparerWEQ_HashCode = mmd;
						else
						{ ;}
					}
					else if(tyname.Equals("System.Collections.Generic.ObjectComparer"))
					{
						if(mname.Equals("DefaultCompare"))
							this.ObjectComparer = mmd;
					}
					else if(tyname.Equals("System.Collections.Generic.StructComparer"))
					{
						if(mname.Equals("DefaultCompare"))
							this.StructComparer = mmd;
					}
					else
					{
						;
					}
				}
			}

			//initialize primitive classes
			ITypeReference[] alltr = supportMod.GetAllTypes().ToArray();

			ITypeReference numvalty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.NumericStackValue"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "NumericStackValue", numvalty);

			ITypeReference boolty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Boolean"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Boolean", boolty);

			ITypeReference sbytety = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.SByte"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "SByte", sbytety);

			ITypeReference bytety = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Byte"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Byte", bytety);

			ITypeReference charty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Char"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Char", charty);

			ITypeReference int16ty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Int16"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Int16", int16ty);

			ITypeReference int32ty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Int32"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Int32", int32ty);

			ITypeReference int64ty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Int64"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Int64", int64ty);

			ITypeReference uint16ty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.UInt16"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "UInt16", uint16ty);

			ITypeReference uint32ty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.UInt32"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "UInt32", uint32ty);

			ITypeReference uint64ty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.UInt64"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "UInt64", uint64ty);

			ITypeReference singlety = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Single"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Single", singlety);

			ITypeReference doublety = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.Double"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "Double", doublety);

			ITypeReference fptrty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.FunctionPtr"));
			this.VisitType_InstantiateAsPrimitiveOrStructType("System", "FunctionPtr", fptrty);

			ITypeReference extstty = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.ExternalState"));
			this.VisitType_InstantiateAsMemoryType("System", "ExternalState", extstty);

			ITypeReference styr = Array.Find(alltr, (ITypeReference tyr) => tyr.ToString().Equals("System.String"));
			this.VisitType_InstantiateAsMemoryType("System", "String", styr);
			
			ITypeReference otyr = supportMod.GetAllTypes().First((ITypeReference tyr) => tyr.ToString().Equals("System.Object"));
			this.VisitType_InstantiateAsMemoryType("System", "Object", otyr);

			this.m_irprog.TypeTable.SetSpecialTypes();
		}

		/// <summary>
		/// Walk all of the types in the module and process them.
		/// </summary>
		public IRProgram Process(IModule m)
		{
			//Main processing of types and rewrite
			INamedTypeDefinition[] alltypes = m.GetAllTypes().ToArray();

			foreach(INamedTypeDefinition ttd in alltypes)
			{
				if(ttd.IsGeneric || ttd.ToString().Contains("<Module>"))
					continue;

				this.VisitType((ITypeDefinition)ttd);
			}

			while(this.m_toProcessTypes.Count != 0 || this.m_toProcessMethods.Count != 0)
			{
				if(this.m_toProcessTypes.Count != 0)
				{
					TypeInstInfo btti = this.m_toProcessTypes.Dequeue();
					WalkTypeDef.ProcessCompleteType(btti.IRType, btti.TyDef, this.m_irprog, this);
				}
				else if(this.m_toProcessMethods.Count != 0)
				{
					MethodInstInfo mtti = this.m_toProcessMethods.Dequeue();
					this.m_optionalT0ReplType = mtti.OptionalInstType;
					
					WalkTypeDef.ProcessMethodDefinition(mtti.MethodIdentity, mtti.MethodDef, this.m_irprog, this);
				}
				else
				{
					;
				}
			}

			WalkTypeDef.DoneWalking();

			return this.m_irprog;
		}

		internal PdbReader GetPDBForType(ITypeReference tyr)
		{
			if(tyr.ToString().StartsWith("System."))
				return this.m_builtinpdb;
			else
				return this.m_modulepdb;
		}

		/// <summary>
		/// Strip off all the pointer/reference indirection on a type.
		/// </summary>
		internal static IRType StripTypeOfAllIndirection(IRType btt)
		{
			IRType tt = btt;
			while(tt is IRPtrType || tt is IRReferenceType)
			{
				if(tt is IRPtrType)
					tt = ((IRPtrType)tt).PtrTargetType;

				if(tt is IRReferenceType)
					tt = ((IRReferenceType)tt).ReferenceTargetType;
			}

			return tt;
		}

		/// <summary>
		/// Process a type name, if the name already exists just return it, otherwise partially instantiate the type and put it on the to process list with the appropriate
		/// module info.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
		internal IRType VisitType(ITypeReference type)
		{
			if(this.m_optionalT0ReplType != null)
			{
				if(type.ToString().Equals("T0"))
					return this.m_optionalT0ReplType;

				if(type.ToString().Contains("<T0>"))
				{
					IRType smplrepl = CCILoader.StripTypeOfAllIndirection(this.m_optionalT0ReplType);
					string ftn = type.ToString().Replace("<T0>", "<" + smplrepl.ToString() + ">");
					return this.m_irprog.TypeTable.LookupTypeForName(ftn);
				}
			}

			if(type is IPointerTypeReference)
			{
				IPointerTypeReference prf = (IPointerTypeReference)type;
				IRType ptt = this.VisitType(prf.TargetType);

				String pttname = ptt.TypeName + "&";
				if(!this.m_irprog.IsTypeNamedInterned(pttname))
				{
					IRReferenceType mptt = new IRReferenceType(ptt.NameSpaceScope, ptt.BaseTypeName + "&", (TypeQualifiers.PublicTag | TypeQualifiers.BuiltinTag), ptt);
					this.m_irprog.InternTypeName(mptt);
				}

				return this.m_irprog.LookupTypeForName(pttname);
			}
			else
			{
				String fulltn = type.ToString();

				if(fulltn.Contains("|Box"))
					throw new ArgumentException("We most likely have a mismatch with the boxing of types check this out.");

				String tnamespace;
				String tbasename;
				int fpp = fulltn.IndexOf("<");
				string nsnn = (fpp != -1 ? fulltn.Substring(0, fpp) : fulltn);
				int lastsplit = nsnn.LastIndexOf('.');
				if(lastsplit != -1)
				{
					tnamespace = fulltn.Substring(0, lastsplit);
					tbasename = fulltn.Substring(lastsplit + 1);
				}
				else
				{
					tnamespace = "";
					tbasename = fulltn;
				}

				if(this.m_irprog.IsTypeNamedInterned(fulltn))
				{
					IRType tt = this.m_irprog.LookupTypeForName(fulltn);

					if(tt is IRClassType)
						return this.m_irprog.TypeTable.LookupPointerTypeFor((IRClassType)tt);
					else
						return tt;
				}
				else
				{
					if(type.IsValueType | type.IsEnum)
						this.VisitType_InstantiateAsPrimitiveOrStructType(tnamespace, tbasename, type);
					else
						this.VisitType_InstantiateAsMemoryType(tnamespace, tbasename, type);

					IRType tt = this.m_irprog.LookupTypeForName(fulltn);
					if(tt is IRClassType)
						return this.m_irprog.TypeTable.LookupPointerTypeFor((IRClassType)tt);
					else
						return tt;
				}
			}
		}

		internal void VisitInvokeIdentity(IRInvokeIdentity iiv, IMethodDefinition md, IRType optinsttype)
		{
			Tuple<IRInvokeIdentity, IRType> ptt = new Tuple<IRInvokeIdentity, IRType>(iiv, optinsttype);
			if(!this.m_pendinganddonemwethods.Contains(ptt))
			{
				this.m_pendinganddonemwethods.Add(ptt);
				this.m_toProcessMethods.Enqueue(new MethodInstInfo(iiv, md, optinsttype));
			}
		}

		///////////////////////////////////////////////////////////////////////////
		//How to create an instantiate each caregory of type we encounter

		/// <summary>
		/// Given a typename for a structure, instantiate the boxed type for the struct.
		/// </summary>
		internal void InstantiateBoxAndPointerTypeForValueType(IRValueType valuety)
		{
			this.m_irprog.TypeTable.InternBoxedTypeFor(valuety);
			this.m_irprog.TypeTable.InternReferenceTypeFor(valuety);
		}

		/// <summary>
		/// Process a type name (a builtin primitive value type) that is not-generic builtin, as a PrimitiveType.
		/// </summary>
		internal void VisitType_InstantiateAsPrimitiveOrStructType(string tnamespace, string tbasename, ITypeReference type)
		{
			IRValueType defty;
			ITypeDefinition ttd = type.ResolvedType;
			TypeQualifiers tq = ExtractTypeQualifiers(ttd);

			bool iskeyvalpair = ttd.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.KeyValPairAttribute"));
			bool isenumerator = ttd.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.EnumeratorAttribute"));

			if(tnamespace.Equals("System") && tbasename.Equals("NumericStackValue"))
				defty = new IRNumericType(tbasename);
			else if(tnamespace.Equals("System") && IRSignedIntegerType.PrimNames.Contains(tbasename))
				defty = new IRSignedIntegerType(tbasename);
			else if(tnamespace.Equals("System") && IRUnSignedIntegerType.PrimNames.Contains(tbasename))
				defty = new IRUnSignedIntegerType(tbasename);
			else if(tnamespace.Equals("System") && IRFloatingPointType.PrimNames.Contains(tbasename))
				defty = new IRFloatingPointType(tbasename);
			else if(tbasename.Equals("FunctionPtr"))
				defty = new IRFunctionPointerType(tnamespace, tbasename, tq);
			else if(ttd.IsEnum)
			{
				IRNumericType underty = (IRNumericType)VisitType(type.ResolvedType.UnderlyingType);
				defty = new IREnumType(tnamespace, tbasename, tq, underty);
			}
			else if(iskeyvalpair)
			{
				defty = new IRKeyValuePairType(tnamespace, tbasename, tq);
			}
			else if(isenumerator)
			{
				IRType enumovertype;
				if(ttd.IsGeneric)
					enumovertype = this.VisitType((((IGenericTypeInstance)ttd).GenericArguments.ToArray())[0]);
				else
					enumovertype = this.m_irprog.TypeTable.RootObjectType;

				defty = new IREnumeratorType(tnamespace, tbasename, tq, enumovertype);
			}
			else
				defty = new IRStructType(tnamespace, tbasename, tq);

			this.m_irprog.InternTypeName(defty);
			this.m_toProcessTypes.Enqueue(new TypeInstInfo(defty, ttd));
		}

		/// <summary>
		/// Process a type name (a class or a interface) that is not-generic, that has been defined in user code and that is a MemoryType.
		/// </summary>
		internal void VisitType_InstantiateAsMemoryType(string tnamespace, string tbasename, ITypeReference type)
		{
			ITypeDefinition ttd = type.ResolvedType;
			TypeQualifiers tq = ExtractTypeQualifiers(ttd);
			IRClassType defty = null;

			bool isLambda = ttd.IsDelegate;
			bool isArray = type is IArrayTypeReference;
			bool isContainer = ttd.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.ContainerAttribute"));
			bool isList = ttd.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.ListAttribute"));
			bool isSet = ttd.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.SetAttribute"));
			bool isDict = ttd.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.DictionaryAttribute"));

			if(isLambda)
			{
				defty = new IRLambdaType(tnamespace, tbasename, tq);
			}
			else if(isArray)
			{
				IRType oftype = VisitType(((IArrayType)ttd).ElementType);
				defty = new IRContainerType(tnamespace, tbasename, tq | TypeQualifiers.BuiltinTag, oftype, true, false, false);
				defty.TypeDescription.LoadFieldInfoAsNeeded(defty, "card", this.m_irprog.TypeTable.Int32Type, SpecialFieldTag.ContainerCardField, FieldQualifiers.PublicTag);
				defty.TypeDescription.LoadFieldInfoAsNeeded(defty, "allf", oftype, SpecialFieldTag.SummaryLocationField, FieldQualifiers.PublicTag);
			}
			else if(isContainer)
			{
				ITypeReference[] gargs = ((IGenericTypeInstance)ttd).GenericArguments.ToArray();
				
				if(isDict)
				{
					IRType keytype = VisitType(gargs[0]);
					IRType valtype = VisitType(gargs[1]);
					IRKeyValuePairType oftype = (IRKeyValuePairType)VisitType(ttd.Fields.First((IFieldDefinition fd) => fd.Name.Value.Equals("allf")).Type);

					defty = new IRDictionaryType(tnamespace, tbasename, tq, oftype);
				}
				else if(isSet)
				{
					IRType oftype = VisitType(gargs[0]);
					defty = new IRContainerType(tnamespace, tbasename, tq, oftype, false, false, true);
				}
				else if(isList)
				{
					IRType oftype = VisitType(gargs[0]);
					defty = new IRContainerType(tnamespace, tbasename, tq, oftype, false, true, false);
				}
				else
					throw new NotImplementedException();
			}
			else
			{
				defty = new IRClassType(tnamespace, tbasename, tq);
			}

			this.m_irprog.InternTypeName(defty);
			this.m_irprog.TypeTable.InternPointerTypeFor(defty);
			this.m_toProcessTypes.Enqueue(new TypeInstInfo(defty, ttd));
		}

		/// <summary>
		/// Extract the type qualifier info for a given type.
		/// </summary>
		private static TypeQualifiers ExtractTypeQualifiers(ITypeDefinition typeDef)
		{
			Contract.Requires(typeDef != null);

			TypeQualifiers tq = TypeQualifiers.Clear;

			if(typeDef is NamespaceTypeDefinition)
				tq = ((NamespaceTypeDefinition)typeDef).IsPublic ? TypeQualifiers.PublicTag : TypeQualifiers.InternalTag;
			else
				tq = TypeQualifiers.PublicTag;

			if(typeDef.IsStatic)
				tq = (tq | TypeQualifiers.StaticTag);

			if(typeDef.IsAbstract)
				tq = (tq | TypeQualifiers.AbstractTag);

			if(typeDef.IsInterface)
				tq = (tq | TypeQualifiers.InterfaceTag);

			bool builtin = typeDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.BuiltinAttribute"));
			if(builtin)
				tq = (tq | TypeQualifiers.BuiltinTag);

			bool specializedimpl = typeDef.Attributes.Any((ICustomAttribute attr) => attr.Type.ToString().Equals("CSharpLibs.Annotations.BuiltinImplementationAttribute"));
			if(specializedimpl)
				tq = (tq | TypeQualifiers.SpcializedImplTag);

			return tq;
		}

		/// <summary>
		/// Given a member field that has been stringified resolve it to an interned static field reference.
		/// </summary>
		internal IRStaticField ResolveStaticFieldRefFromString(String fname)
		{
			int splitidx = fname.LastIndexOf('.');
			String tname = fname.Substring(0, splitidx);
			IRType declt = this.m_irprog.TypeTable.LookupTypeForName(tname);
			String f = fname.Substring(splitidx + 1);

			return this.m_irprog.NameTable.LookupStaticField(declt, f);
		}
	}

	/// <summary>
	/// If we encounter a type reference we create one of these to note the information we use in later instantiations.
	/// </summary>
	internal class TypeInstInfo
	{
		internal IRType IRType;
		internal ITypeDefinition TyDef;
		
		internal TypeInstInfo(IRType ttmtsa, ITypeDefinition tt)
		{
			this.IRType = ttmtsa;
			this.TyDef = tt;
		}
	}

	/// <summary>
	/// If we encounter a type reference we create one of these to note the information we use in later instantiations.
	/// </summary>
	internal class MethodInstInfo
	{
		internal IRInvokeIdentity MethodIdentity;
		internal IMethodDefinition MethodDef;
		internal IRType OptionalInstType;

		internal MethodInstInfo(IRInvokeIdentity ttmtsa, IMethodDefinition mdef, IRType insttype)
		{
			Contract.Requires(mdef != Dummy.MethodBody);

			this.MethodIdentity = ttmtsa;
			this.MethodDef = mdef;
			this.OptionalInstType = insttype;
		}
	}
}

